#include <cmath>

#include "calculador_de_ganancia.h"
#include "clasificador_de_alumnos_por_descriptor.h"

double CalculadorDeGanancia::calcularProbabilidadDeTrue(Lista<Alumno*>* alumnos, DescriptorAlumno descriptor) {

	int cantidadAlumnosConDescriptorTrue = 0;

	IteradorLista<Alumno*> iteradorAlumnos = alumnos->iterador();

	while(iteradorAlumnos.tieneSiguiente() == true){
		Alumno * unAlumno = iteradorAlumnos.siguiente();
		if(unAlumno->getValorDelDescriptor(descriptor) == true){
			cantidadAlumnosConDescriptorTrue++;
		}
	}

	if(alumnos->tamanio() == 0){
		return 0;
	}

	return (cantidadAlumnosConDescriptorTrue / alumnos->tamanio());
}

double CalculadorDeGanancia::calcularEntropia(Lista<Alumno*>* alumnos) {

	double probabilidadDeCalificadorTrue = this->calcularProbabilidadDeTrue(alumnos, PROMEDIO_MAYOR_A_CUATRO);
	double probabilidadDeCalificadorFalse = 1 - probabilidadDeCalificadorTrue;

	if(probabilidadDeCalificadorTrue < 0.00000001 || probabilidadDeCalificadorFalse < 0.00000001){
		return 0;
	}

	return - probabilidadDeCalificadorTrue * log2(probabilidadDeCalificadorTrue) - probabilidadDeCalificadorFalse * log2(probabilidadDeCalificadorFalse);
}

double CalculadorDeGanancia::calcularGananciaDelDescriptor(Lista<Alumno*>* alumnos, DescriptorAlumno descriptor){

	if(alumnos->estaVacia()){
		return 0;
	}

	double entropiaDelTotal = this->calcularEntropia(alumnos);
	double probabilidadDeDesrciptorTrueEnElTotal = this->calcularProbabilidadDeTrue(alumnos, descriptor);
	double probabilidadDeDesrciptorFalseEnElTotal = 1 - probabilidadDeDesrciptorTrueEnElTotal;

	ClasificadorDeAlumnosPorDescriptor clasificador;
	ClasificacionDeAlumnosPorDescriptor *clasificacion = clasificador.clasificarAlumnos(alumnos, descriptor);

	double entropiaDelConjuntoConDescriptorTrue = this->calcularEntropia(clasificacion->getListaVerdadero());
	double entropiaDelConjuntoConDescriptorFalse = this->calcularEntropia(clasificacion->getListaFalso());

	delete clasificacion->getListaVerdadero();
	delete clasificacion->getListaFalso();
	delete clasificacion;

	return entropiaDelTotal - probabilidadDeDesrciptorTrueEnElTotal * entropiaDelConjuntoConDescriptorTrue - probabilidadDeDesrciptorFalseEnElTotal * entropiaDelConjuntoConDescriptorFalse;
}

DescriptorAlumno CalculadorDeGanancia::descriptorConMayorGanancia(Lista<Alumno*>* alumnos, ConjuntoDeDescriptores descriptores){

	IteradorLista<DescriptorAlumno> iterador = descriptores.iterador();

	DescriptorAlumno mejorDescriptor = iterador.siguiente();
	double mayorGanancia = this->calcularGananciaDelDescriptor(alumnos, mejorDescriptor);;

	while(iterador.tieneSiguiente()){
		DescriptorAlumno unDescriptor = iterador.siguiente();
		double unaGanancia = this->calcularGananciaDelDescriptor(alumnos, unDescriptor);

		if(unaGanancia > mayorGanancia){
			mayorGanancia = unaGanancia;
			mejorDescriptor = unDescriptor;
		}
	}

	return mejorDescriptor;
}
